<template>
  <el-table
      border
      stripe class="table-header">
    <el-table-column prop="index" label="序号" width="80"></el-table-column>
    <el-table-column prop="name" label="姓名" width="120"></el-table-column>
    <el-table-column prop="age" label="年龄" width="80"></el-table-column>
    <el-table-column prop="address" label="地址"></el-table-column>
  </el-table>
  <div
      class="virtual-table-container"
      ref="containerRef"
      v-el-table-infinite-scroll="{ callback: loadMoreData }"
      @scroll="handleScroll">
    <div class="virtual-table-placeholder" :style="{ height: totalHeight + 'px' }"></div>
    <div class="virtual-table-content" :style="{ transform: `translateY(${offsetY}px)` }">
      <el-table
          v-loading="isLoading"
          :data="visibleData" border stripe :header-cell-style="{ display: 'none' }">
        <el-table-column prop="index" label="序号" width="80"></el-table-column>
        <el-table-column prop="name" label="姓名" width="120"></el-table-column>
        <el-table-column prop="age" label="年龄" width="80"></el-table-column>
        <el-table-column prop="address" label="地址"></el-table-column>
      </el-table>
    </div>
  </div>
</template>

<script setup>
import {ref, reactive, computed, onMounted, watch, nextTick} from 'vue';

const itemHeight = ref(40);
const bufferSize = ref(5);
const containerRef = ref(null);
const tableHeight = ref(0);
const tableList = ref([]);
const visibleData = ref([]);
const offsetY = ref(0);
const isLoading = ref(false);
const isMore = ref(false);
const hasMore = ref(true);
const totalHeight = computed(() => itemHeight.value * tableList.value.length);
const visibleCount = computed(() => Math.ceil(tableHeight.value / itemHeight.value));
const queryParams = {
  pageSize: 10000,
  pageNum: 1,
};

const calculateVisibleRange = () => {
  const container = containerRef.value;
  if (!container) return {start: 0, end: 0};

  const scrollTop = container.scrollTop;
  const startIndex = Math.floor(scrollTop / itemHeight.value);
  const endIndex = Math.min(
      startIndex + visibleCount.value + bufferSize.value * 2,
      tableList.value.length
  );

  return {start: Math.max(0, startIndex - bufferSize.value), end: endIndex};
};

const updateVisibleData = () => {
  const {start, end} = calculateVisibleRange();
  visibleData.value = tableList.value.slice(start, end);
  offsetY.value = start * itemHeight.value;
};

const handleScroll = () => {
  updateVisibleData();
};

const generateData = () => {
  const result = [];
  const startIndex = tableList.value.length;
  for (let i = 0; i < queryParams.pageSize; i++) {
    result.push({
      index: i + startIndex + 1,
      name: `用户${i + startIndex + 1}`,
      age: Math.floor(Math.random() * 50) + 18,
      address: `北京市朝阳区建国路88号院${i + startIndex + 1}号楼${Math.floor(Math.random() * 1000) + 101}室`,
    });
  }
  queryParams.pageNum++;
  return result;
};

function getData() {
  isLoading.value = true;
  isMore.value = true
  setTimeout(() => {
    isMore.value = false
    isLoading.value = false;
    const newData = generateData();
    tableList.value = [...tableList.value, ...newData];
  }, 2000);
}

const loadMoreData = () => {
  console.log("加载了更多 页码>>", queryParams.pageNum)
  getData();
  return new Promise((resolve) => {
    resolve();
  });
};

onMounted(() => {
  nextTick(() => {
    // 获取容器实际高度
    if (containerRef.value) {
      tableHeight.value = containerRef.value.clientHeight;
    }
    updateVisibleData();
  });
  getData();

});

// 监听数据源变化
watch(() => tableList.value, () => {
  updateVisibleData();
});
</script>

<style scoped>
.virtual-table-container {
  height: calc(100vh - 200px);
  overflow: auto;
  position: relative;
}

.virtual-table-placeholder {
  width: 100%;
}

.virtual-table-content {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
}

.table-header ::v-deep .el-table__body-wrapper {
  display: none;
}
</style>